package lvq;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;

import javax.swing.JFrame;
import javax.swing.JPanel;

@SuppressWarnings("serial")
public class Grafico extends JPanel {

	private Rede rede;
	private Dados dados;
	int deslocamento;

	public Grafico(Rede rede, Dados dados) {

		this.rede = rede;
		this.dados = dados;
		this.deslocamento = 300;
	}

	@Override
	public final void paint(Graphics g1) {

		Graphics2D g = inicializaPainel(g1);

		imprimeEixos(g, deslocamento);

		imprimeDados(g);
		
		imprimeVizinhanca(g);

		imprimeNeuronios(g);
	}

	private Graphics2D inicializaPainel(Graphics g1) {

		Graphics2D g = (Graphics2D) g1;

		g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		g.translate(deslocamento, deslocamento);
		g.scale(-1, 1);

		g.setColor(Color.WHITE);
		g.fillRect(-deslocamento, -deslocamento, deslocamento * 2, deslocamento * 2);

		return g;
	}

	private void imprimeEixos(Graphics2D g, int deslocamento) {

		g.setColor(Color.BLACK);

		Line2D.Double x = new Line2D.Double(0, -deslocamento, 0, deslocamento);
		g.draw(x);

		Line2D.Double y = new Line2D.Double(-deslocamento, 0, deslocamento, 0);
		g.draw(y);
	}

	private void imprimeDados(Graphics2D g) {

		g.setColor(Color.RED);

		for (int i = 0; i < dados.quantidadeDados(); i++) {
			imprimeDado(g, dados.obtemCoordenadas(i));
		}
	}

	private void imprimeDado(Graphics2D g, double[] coordenadas) {

		double x = coordenadas[0] * 10;
		double y = coordenadas[1] * 10;

		Line2D.Double linha1 = new Line2D.Double(x + 2, y, x - 2, y);
		g.draw(linha1);

		Line2D.Double linha2 = new Line2D.Double(x, y + 2, x, y - 2);
		g.draw(linha2);
	}

	private void imprimeNeuronios(Graphics2D g) {

		g.setColor(Color.BLUE);

		for (int i = 0; i < rede.largura(); i++) {
			for (int j = 0; j < rede.altura(); j++) {
				imprimeNeuronio(g, rede.neuronios()[i][j]);
			}
		}
	}

	private void imprimeNeuronio(Graphics2D g, Neuronio neuronio) {

		double x = neuronio.coordenadas()[0] * 10;
		double y = neuronio.coordenadas()[1] * 10;

		Ellipse2D.Double ponto = new Ellipse2D.Double(x - 2.5, y - 2.5, 5, 5);
		g.fill(ponto);
	}

	private void imprimeVizinhanca(Graphics2D g) {

		g.setColor(Color.GREEN);

		double x, y;

		for (int i = 0; i < rede.largura(); i++) {
			for (int j = 0; j < rede.altura(); j++) {

				x = rede.neuronios()[i][j].coordenadas()[0] * 10;
				y = rede.neuronios()[i][j].coordenadas()[1] * 10;

				try {vizinhoDireita(g, x, y, i, j);} catch (Exception e) {}
				try {vizinhoBaixo(g, x, y, i, j);} catch (Exception e) {}
				try {vizinhoDiagonalEsquerda(g, x, y, i, j);} catch (Exception e) {}
//				try {vizinhoDiagonalDireita(g, x, y, i, j);} catch (Exception e) {}
			}
		}

	}

	private void vizinhoDireita(Graphics2D g, double x, double y, int i, int j) {

		double vizinhoX;
		double vizinhoY;
		vizinhoX = rede.neuronios()[i + 1][j].coordenadas()[0] * 10;
		vizinhoY = rede.neuronios()[i + 1][j].coordenadas()[1] * 10;
		Line2D.Double vizinhoEsquerda = new Line2D.Double(x, y, vizinhoX, vizinhoY);
		g.draw(vizinhoEsquerda);
	}

	private void vizinhoBaixo(Graphics2D g, double x, double y, int i, int j) {

		double vizinhoX;
		double vizinhoY;
		vizinhoX = rede.neuronios()[i][j + 1].coordenadas()[0] * 10;
		vizinhoY = rede.neuronios()[i][j + 1].coordenadas()[1] * 10;
		Line2D.Double vizinhoBaixo = new Line2D.Double(x, y, vizinhoX, vizinhoY);
		g.draw(vizinhoBaixo);
	}

	private void vizinhoDiagonalEsquerda(Graphics2D g, double x, double y, int i, int j) {

		double vizinhoX;
		double vizinhoY;
		vizinhoX = rede.neuronios()[i + 1][j + 1].coordenadas()[0] * 10;
		vizinhoY = rede.neuronios()[i + 1][j + 1].coordenadas()[1] * 10;
		Line2D.Double vizinhoDiagonal = new Line2D.Double(x, y, vizinhoX, vizinhoY);
		g.draw(vizinhoDiagonal);
	}
	
	@SuppressWarnings("unused")
	private void vizinhoDiagonalDireita(Graphics2D g, double x, double y, int i, int j) {
		
		double vizinhoX;
		double vizinhoY;
		vizinhoX = rede.neuronios()[i + 1][j - 1].coordenadas()[0] * 10;
		vizinhoY = rede.neuronios()[i + 1][j - 1].coordenadas()[1] * 10;
		Line2D.Double vizinhoDiagonal = new Line2D.Double(x, y, vizinhoX, vizinhoY);
		g.draw(vizinhoDiagonal);
	}

	public void mostraDados() {

		int tamanhoJanelaX = deslocamento * 2 + 16;
		int tamanhoJanelaY = deslocamento * 2 + 39;

		JFrame frame = new JFrame();

		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setTitle("Self Organizing Maps");
		frame.setBounds(50, 50, tamanhoJanelaX, tamanhoJanelaY);
		frame.setContentPane(this);

		frame.setVisible(true);
	}
}
